package com.io.netty.dubborpc.netty;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.concurrent.Callable;

public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable {

    private ChannelHandlerContext myCtx;//上下文
    private String result; //返回的结果
    private String para; //客户端调用方法时，传入的参数

    //与服务器的连接创建后，就会被调用, 这个方法是第一个被调用(1)（好像是handler加入管道时被调用）
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(" channelActive 被调用  ");
        myCtx = ctx; //因为我们在其它方法会使用到 ctx
    }

    //这个方法是由nioEventLoopGroup-2-1这个线程来调用的，跟调用call的不是一个线程
    //所以需要线程之间的通信
    //收到服务器的数据后，调用方法 (4)
    public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println(" channelRead 被调用  ");
        result = msg.toString();
        System.out.println(Thread.currentThread().getName()+"：唤醒另一个线程");
        //唤醒等待当前对象的线程
        notify();
    }

    //值得注意的是，这个方法是由executor中的四个线程循环执行的
    //先使用这个方法来相服务器发送消息,这个方法加了同步锁，锁的是当前对象
    //被代理对象调用, 发送数据给服务器，-> wait -> 等待被唤醒(channelRead) -> 返回结果 (3)-》5
    public synchronized Object call() throws Exception {
        //实际开发中应该传递的是一个信息，告诉服务器客户端要调用哪个方法
        //然后服务器把方法调用的结果在通过网络传输过来
        System.out.println(" call1 被调用  ");

        //这发送的是一个字符串，实际是放在缓冲区中来进行发送的，前面在管道中加入了netty提供的编码器
        //编码器应该是会把字符串变成字节，然后在把字节放在缓冲区中（只有字节才能在网络中进行传输）
        myCtx.writeAndFlush(para);
        System.out.println(Thread.currentThread().getName()+"：我把数据写出去，我睡了。。");
        //等待服务器端方法调用结果的返回值，拿到返回值之后客户端才能进行下一步的业务处理
        //等待channelRead方法获取到服务器的结果后，拿到结果之后才会唤醒
        wait();
        System.out.println(" call2 被调用  ");
        //然后进行下一步的业务处理，这里并没有处理什么业务，把服务器返回的结果进行了返回
        return  result;
    }

    //(2)
    void setPara(String para) {
        System.out.println(" setPara  ");
        this.para = para;
    }

    //处理器发生异常会调用这个方法
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }

}
